﻿using System;
using System.Text;
using msilgc.cbuilder.CSyntaxTree;

namespace msilgc.CSyntaxTree {
    internal class ArithmeticStatement : ICStatementWithAssignment {
        public IVariable Target { get; set; }
        public bool OnStack { get; set; }
        public IVariable Operand1 { get; set; }
        public IVariable Operand2 { get; set; }
        public Operation Op { get; set; }

        public ArithmeticStatement(IVariable target, IVariable operand1, IVariable operand2, Operation op) {
            Target = target;
            Operand1 = operand1;
            Operand2 = operand2;
            Op = op;
            OnStack = true;
        }

        private static string GetSimpleOp(Operation op) {
            switch (op) {
                case Operation.And:
                    return "&";
                case Operation.Add:
                    return "+";
                case Operation.Div:
                    return "/";
                case Operation.Mul:
                    return "*";
                case Operation.Or:
                    return "|";
                case Operation.Rem:
                    return "%";
                case Operation.Sub:
                    return "-";
                case Operation.Xor:
                    return "^";
                default:
                    throw new Exception("unexpected operation");
            }
        }
        
        private static string GetComplexOp(Operation op) {
            switch (op) {
                case Operation.Ceq:
                    return " == 0 ";
                case Operation.Cgt:
                    return " > 0 ";
                case Operation.Clt:
                    return " < 0 ";
                default:
                    throw new Exception("unexpected operation");
            }
        }

        public void Emit(StringBuilder builder) {
            switch (Op) {
                case Operation.And:
                case Operation.Add:
                case Operation.Div:
                case Operation.Mul:
                case Operation.Or:
                case Operation.Rem:
                case Operation.Sub:
                case Operation.Xor: {
                        Target.Emit(builder);
                        builder.Append(" = ");
                        Operand1.Emit(builder);
                        builder.Append(" ");
                        builder.Append(GetSimpleOp(Op));
                        builder.Append(" ");
                        Operand2.Emit(builder);
                        builder.AppendLine(";");
                    }
                    break;
                case Operation.Ceq:
                case Operation.Cgt:
                case Operation.Clt: {
                        builder.Append("if(");
                        Operand1.Emit(builder);
                        builder.Append(" - ");
                        Operand2.Emit(builder);
                        builder.Append(GetComplexOp(Op));
                        builder.Append(") { ");
                        Target.Emit(builder);
                        builder.Append(" = 1; } else { ");
                        Target.Emit(builder);
                        builder.AppendLine(" = 0; }");
                    }
                    break;
                default:
                    throw new Exception("unknown operation type");
            }
        }
    }

    public enum Operation {
        Add,
        And,
        Ceq,
        Cgt,
        Clt,
        Div,
        Mul,
        Or,
        Rem,
        Sub,
        Xor
    }
}
